%{
	#include <stdio.h>
	#include "../model/datatypes.h"
	#include "../model/globals.h"
	#include "../model/internal_kb.h"
	#include "../model/limits.h"

	#define YYSTYPE Expression
	int yylex(void);
	int yylineno;
	void yyerror(char *);
	FILE *yyin; 		/* Input for yacc parser. */

	// for parsing conjunction
	int cls_exp_count;	/* number of conjuncts for conjunction */
	Concept* cls_exps[MAX_CONJUNCT_COUNT]; /* conjuncts */

	// for parsing role composition
	int role_exp_count;
	Role* role_exps[MAX_ROLE_COMPOSITION_SIZE];
	char parsing_role_inclusion;

	char parsing_transitive_role;

	// temporary solution, should be improved!
	char parsing_prefix;

	/* for keeping track of nested conjunctions in order to flatten them */
	enum concept_description_type  parse_stack[MAX_CONJ_EXISTS_ALTERNATION];
	int parse_stack_top = 0;
%}

%token PREFIX ONTOLOGY IMPORT BASEIRI FULLIRI
%token IDENTIFIER OBJECTSOMEVALUESFROM OBJECTINTERSECTIONOF DECLARATION CLASS
%token OBJECTPROPERTY SUBOBJECTPROPERTYOF OBJECTPROPERTYCHAIN TRANSITIVE_OBJECT_PROPERTY
%token EQUIVALENTCLASSES SUBCLASSOF 

%%

ontologyDocument:
	prefixDeclaration ontology
	;
prefixDeclaration:
//	| prefixDeclaration PREFIX '(' prefixName ':' '=' BASEIRI ')' 
	| prefixDeclaration PREFIX '(' prefixName '=' BASEIRI ')' 
	;

prefixName:
	IDENTIFIER
	;

ontology:
	ONTOLOGY '(' BASEIRI axioms ')' 
	;

axiom:
	classAxiom | objectPropertyAxiom
	;

 /* 5.8  Entity Declarations and Typing */
 // Declarations are ignored by the lexical analyzer since they are irrelevant
 // for reasoning
 // declaration:
 // 	DECLARATION '(' entity ')'
 //	;
 // entity:
 // 	CLASS '(' class ')' | OBJECTPROPERTY '(' objectProperty ')'
 // 	;

classAxiom:
	subClassAxiom
	| equivalentClassAxiom
	;

objectPropertyAxiom:
	subObjectPropertyOf
	| transitiveObjectProperty
	;

axioms:
	axiom
	| axioms axiom
	;


subClassAxiom:
	SUBCLASSOF '(' classExpression classExpression ')'	{
		tbox.axioms[tbox.axiom_count] = create_subclass_axiom($3.concept,$4.concept);
		++tbox.axiom_count;
		++subclass_ax_count;
	}
	;

equivalentClassAxiom:
	EQUIVALENTCLASSES '(' classExpression classExpression ')' {
		tbox.axioms[tbox.axiom_count] = create_eqclass_axiom($3.concept,$4.concept);
		++tbox.axiom_count;
		++eqclass_ax_count;
	}
	;

	/* TODO: add TOP! */
// class:
// 	FULLIRI 
// 	;
class:
	FULLIRI 
	;

classExpression:
	class			{ $$.concept = $1.concept; }
	| objectIntersectionOf  {
				 $$.concept = $1.concept; 
				}
	| objectSomeValuesFrom  {
				 $$.concept = $1.concept; 
				}
	;
	
	
objectIntersectionOf:
	OBJECTINTERSECTIONOF '(' classExpression classExpression classExpressions ')'				{
/*
				 if (parse_stack_top >= 2 && parse_stack[parse_stack_top - 2] == CONJUNCTION) {
				 	cls_exps[cls_exp_count++] = $3.concept;
				 	cls_exps[cls_exp_count++] = $4.concept;
					$$.concept = NULL;
				 }
				 else {
					if ($3.concept != NULL)
				 		cls_exps[cls_exp_count++] = $3.concept;
					if ($4.concept != NULL)
				 		cls_exps[cls_exp_count++] = $4.concept;
				 	$$.concept = create_conjunction(cls_exp_count,cls_exps);
				 	cls_exp_count = 0;
				 }
				 --parse_stack_top;
*/
				 	cls_exps[cls_exp_count++] = $3.concept;
				 	cls_exps[cls_exp_count++] = $4.concept;
				 	$$.concept = create_conjunction(cls_exp_count,cls_exps);
				 	cls_exp_count = 0;
				}

	;

objectSomeValuesFrom:
	OBJECTSOMEVALUESFROM '(' objectPropertyExpression classExpression ')' {
				 $$.concept = create_exists($3.role,$4.concept);
				 // --parse_stack_top;
				}
	;

objectPropertyExpression:
	objectProperty { $$.role = $1.role; }
	;

subObjectPropertyOf:
	SUBOBJECTPROPERTYOF '(' subObjectPropertyExpression superObjectPropertyExpression ')' {
		tbox.axioms[tbox.axiom_count] = create_subrole_axiom($3.role,$4.role);
		++tbox.axiom_count;
		++subrole_ax_count;
		parsing_role_inclusion = 0;
	}
	;

subObjectPropertyExpression : 
	objectPropertyExpression 
	| propertyExpressionChain
	;

propertyExpressionChain : 
	OBJECTPROPERTYCHAIN '(' objectPropertyExpression objectPropertyExpression objectPropertyExpressions  ')' {
		role_exps[role_exp_count++] = $3.role;
		role_exps[role_exp_count++] = $4.role;
		$$.role = create_role_composition(role_exp_count, role_exps);
		role_exp_count = 0;
	}
	;

objectPropertyExpressions :
	|
	objectPropertyExpressions objectPropertyExpression {
		role_exps[role_exp_count++] = $2.role;
	}
	;

superObjectPropertyExpression : 
	objectPropertyExpression
	;

transitiveObjectProperty:
	TRANSITIVE_OBJECT_PROPERTY  '(' objectPropertyExpression ')' {
		printf("TransitiveObjectProperty\n");
		$$.role = $3.role;
		parsing_transitive_role = 0;
	}
	;

 /* 5.3 Object Properties */
objectProperty:
	FULLIRI 
	;

classExpressions:
	| 
	// classExpressions classExpression {
	classExpression classExpressions {
		if ($1.concept != NULL)
			cls_exps[cls_exp_count++] = $1.concept;
	}
	;
	

%%

void yyerror(char *s) {
	fprintf(stderr, "\nline %d: %s\n", yylineno, s);
}
